﻿using System;
using System.Data;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Configuration;
using System.Xml;
using HtmlAgilityPack;
using MiniCrawler.Business;
using MiniCrawler.Logging;
using MiniCrawler.Models;

namespace MiniCrawler
{
    public class Utils
    {
        #region Common

        /// <summary>
        /// Get value of lookup field
        /// </summary>   
        /// <param name="lookupvalue"></param>
        /// <returns></returns>
        public static string GetValueLookupField(string lookupvalue)
        {
            string result = lookupvalue;
            var arr = lookupvalue.Split(new string[] { ";#" }, StringSplitOptions.RemoveEmptyEntries);
            if (arr.Length > 1)
            {
                result = arr[1];
            }
            return result.Replace("0;#", "");
        }

        /// <summary>
        /// Check empty datarow item
        /// </summary>
        /// <param name="row"></param>
        /// <param name="rowName"></param>
        /// <param name="nullValue"></param>
        /// <returns></returns>
        public static String CheckEmptyDataRowItem(DataRow row, String rowName, String nullValue)
        {
            try
            {
                return row[rowName].ToString();
            }
            catch (System.ArgumentException)
            {
                return nullValue;
            }
        }

        #endregion

        #region Crawler Data

        #region Add ListItem List CMS_News

        /// <summary>
        /// Method Compare Datetime
        /// </summary>
        /// <param name="timenew"></param>
        /// <param name="timeold"></param>
        /// <returns></returns>
        private static bool CompareDateTime(DateTime timenew, DateTime timeold)
        {
            try
            {

                int result = DateTime.Compare(timenew, timeold);
                if (result > 0)
                    return true;
                else
                    return false;

            }
            catch (Exception ex)
            {

                LogService.Service.Error(ex);
                return true;
            }
        }
        #endregion

        #region Write console
        public static void WriteLog(string s)
        {
            Console.Write(s + "\r\n");
            LogService.Service.Info(s + "\r\n");
        }
        #endregion


        public static string GetAttribute(HtmlNode node, string attribute)
        {
            var lnk = node.Attributes[attribute];
            if (lnk != null)
            {
                string s = lnk.Value;
                return s;
            }
            return string.Empty;
        }

        public static string GetInnerText(HtmlNode node)
        {
            return node.InnerText.Replace("\r", string.Empty)
                .Replace("\n", string.Empty)
                .Replace("\t", string.Empty);
        }

        #endregion

        public static void SetCellValue(DataRow dr, string column, string value)
        {
            dr[column] = value;
        }
        public static string GetCellValue(DataRow dr, string column)
        {

            try
            {
                if (dr.Table.Columns.Contains(column) &&
                    dr[column] != null &&
                    !string.IsNullOrEmpty(dr[column].ToString()))
                    return dr[column].ToString();
                else
                {
                    return string.Empty;
                }
            }
            catch (Exception ex)
            {
                LogService.Service.Error("Error at column : " + column + "\n ---- Exception " + ex);
                throw;
                return string.Empty;
            }
        }

        public static string GetCellValue(DataRow dr, string column, string resultIfNull)
        {

            try
            {
                if (dr.Table.Columns.Contains(column) && dr[column] != null && !string.IsNullOrEmpty(dr[column].ToString()))
                    return dr[column].ToString();
                else
                {
                    return resultIfNull;
                }
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                throw;
                return string.Empty;
            }
        }
        public static string GetValue(object obj)
        {
            try
            {
                if (obj != null)
                {
                    return obj.ToString();
                }
                else
                {
                    return string.Empty;
                }
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                throw;
                return string.Empty;
            }

        }

        public static List<string> ExtractImageLinksFromHtml(string html)
        {
            try
            {
                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                List<string> result = new List<string>();
                doc.LoadHtml(html);

                var imageNodeCollection = doc.DocumentNode.SelectNodes("//img");
                if (imageNodeCollection != null && imageNodeCollection.Count > 0)
                {
                    foreach (HtmlNode image in imageNodeCollection)
                    {
                        HtmlAttribute att = image.Attributes["src"];
                        if (att != null)
                        {
                            var m = att.Value;
                            result.Add(m);
                        }

                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return new List<string>();
            }

        }

        public static string ReplaceAbsoluteImageUrl(string hostname, string html)
        {
            try
            {
                List<string> result = Utils.ExtractImageLinksFromHtml(html);

                var content = html;
                if (result.Count > 0)
                {
                    foreach (var url in result)
                    {
                        if (url.StartsWith("/"))
                        {
                            content = content.Replace(url, hostname + url);
                        }
                    }

                    // Update content
                    return content;
                }
                return html;
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return string.Empty;
            }

        }


        
        public static List<string> GetAllLinks(string html)
        {
            try
            {
                List<string> result = new List<string>();
                var doc = new HtmlDocument();
                doc.LoadHtml(html);

                // Select all category nodes with class = 'jazin-section'
                var allLinks = doc.DocumentNode.SelectNodes("//a");

                // Get all urls of nodes
                foreach (HtmlNode link in allLinks)
                {
                    HtmlAttribute att = link.Attributes["href"];
                    if (att != null && att.Value != null)
                    {
                        var m = att.Value;
                        result.Add(m);
                    }
                }
                return result;
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return new List<string>();
            }
        }


        public static int GetNumberOfChecked(List<NewsLink> links)
        {
            int i = 0;
            foreach (NewsLink link in links)
            {
                if (link.Checked) i++;
            }
            return i;

        }
        public static int GetNumberOfChecked(List<CategoryLink> links)
        {
            int i = 0;
            foreach (CategoryLink link in links)
            {
                if (link.Checked) i++;
            }
            return i;

        }

        public static bool IsContainNewsLink(List<NewsLink> links, string url)
        {
            bool result = false;
            foreach (NewsLink link in links)
            {
                if (link.Link.Equals(url) || link.Link.Contains(url)) return true;
            }
            return result;

        }
        public static bool IsFullyCheckedNewsLink(List<NewsLink> links)
        {
            bool result = true;
            foreach (NewsLink link in links)
            {
                if (!link.Checked) return false;
            }
            return result;
        }

        public static bool IsContainCategoryLink(List<CategoryLink> links, string url)
        {
            bool result = false;
            foreach (CategoryLink link in links)
            {
                if (link.Link.Equals(url) || link.Link.Contains(url)) return true;
            }
            return result;

        }
        public static bool IsFullyCheckedCategoryLink(List<CategoryLink> links)
        {
            bool result = true;
            foreach (CategoryLink link in links)
            {
                if (!link.Checked) return false;
            }
            return result;
        }

        public static List<CategoryLink> GetAllCategoryLinks(List<CategoryLink> oldLinks, List<string> allLinks)
        {
            var t = oldLinks;

            if (allLinks.Count > 0)
            {
                foreach (var link in allLinks)
                {
                    
                    if (IsCategoryLink(link) && !IsContainCategoryLink(t, link))
                    {
                        Log.WriteLog("[ADD CATEGORY]" + link);
                        t.Add(new CategoryLink(link, false));
                    }
                }
            }
            return t;
        }

        public static List<NewsLink> GetAllNewsLink(List<NewsLink> oldLinks, List<string> allLinks)
        {
            var t = oldLinks;
            if (allLinks.Count > 0)
            {
                foreach (var link in allLinks)
                {
                    
                    if (IsNewsLink(link) && !IsContainNewsLink(t, link))
                    {
                        Log.WriteLog("[ADD NEWS]" + link);
                        t.Add(new NewsLink(link, false));
                    }
                }
            }
            return t;
        }



        public static bool IsTagLink(string link)
        {
            // /vi/tin-vca/diem-tin.html 
            return (link.Contains("/tag/") || link.Contains("/mailto/"));

        }
        public static bool IsCategoryLink(string link)
        {
            // /vi/tin-vca/diem-tin.html 
            int t = link.LastIndexOf('/');

            if (t >= link.Length - 1) return false;
            if (!link.StartsWith("/")) return false;
            if (IsTagLink(link)) return false;
            if (!link.EndsWith(".html")) return false;

            string s = link.Substring(link.LastIndexOf('/') + 1, 1);
            if (!IsNumeric(s))
                return true;
            else return false;
        }

        public static bool IsNewsLink(string link)
        {
            // /vi/tin-vca/diem-tin.html 

            int t = link.LastIndexOf('/');

            if (t >= link.Length - 1) return false;
            if (!link.StartsWith("/")) return false;
            if (IsTagLink(link)) return false;
            if (!link.EndsWith(".html")) return false;

            string s = link.Substring(link.LastIndexOf('/') + 1, 1);
            if (IsNumeric(s))
                return true;
            else return false;
        }

        private static bool IsNumeric(string number)
        {
            int t = -1;
            var x = int.TryParse(number, out t);
            return x;
        }



        #region Generate Dynamic ID

        /// <summary>
        /// Get ID by Truong,DateTime,Max: MaBV.Nam/Thang/Ngay.00000max
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public static string GetUniqueId(string param)
        {
            string strReturn = "";

            Random random = new Random();

            strReturn = param + "." + ConvertDateTimeToYYYYMMDDSS(DateTime.Now) + "." +
                        ConvertNumberToString(random.Next(999999), 6);

            return strReturn;
        }

        /// <summary>
        /// Return ddmmyyyy
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string ConvertDateTimeToYYYYMMDDSS(DateTime date)
        {
            string str = "";
            str += date.Year.ToString();
            str += ConvertNumberToString(date.Month, 2);
            str += ConvertNumberToString(date.Day, 2);
            str += ConvertNumberToString(date.Hour, 2);
            str += ConvertNumberToString(date.Minute, 2);
            str += ConvertNumberToString(date.Second, 2);
            return str;
        }

        /// <summary>
        /// Convert number to string 123 to 000123
        /// </summary>
        /// <param name="number"></param>
        /// <param name="numberStandard"></param>
        /// <returns></returns>
        public static string ConvertNumberToString(int number, int numberStandard)
        {
            string result = number.ToString();
            if (numberStandard >= result.Length)
            {
                int numberZero = numberStandard - result.Length;
                if (numberZero > 0)
                {
                    result = GetStringZero(numberZero) + result;
                }
            }
            return result;
        }

        /// <summary>
        ///Get string zero 
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static string GetStringZero(int number)
        {
            string result = String.Empty;
            if (number > 0)
            {
                for (int i = 1; i <= number; i++)
                {
                    result += "0";
                }
            }
            return result;
        }

        #endregion
    }
}
